/**
 * Copyright (c) 2017-present, Facebook, Inc. and its affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree.
 */
#include "logdevice/admin/maintenance/test/MaintenanceTestUtil.h"

#include "logdevice/common/test/NodesConfigurationTestUtil.h"

namespace facebook { namespace logdevice { namespace maintenance {

std::shared_ptr<const NodesConfiguration> genNodesConfiguration() {
  return NodesConfigurationTestUtil::provisionNodes();
}

std::unique_ptr<thrift::ClusterMaintenanceState> genMaintenanceState() {
  // This assumes the nodes configuration generated by
  // genNodesConfiguraion. See the specifications of this configuration in
  // logdevice/common/test/NodesConfigurationTestUtil.h
  auto output = std::make_unique<thrift::ClusterMaintenanceState>();
  output->set_version(123);

  //
  // Some storage nodes (N1 (ST, SEQ), N2 (METADATA), N11 (ST, SEQ), N7 (SEQ))
  //
  auto N1 = thrift::NodeID();
  N1.set_node_index(1);
  auto N1S0 = thrift::ShardID();
  N1S0.set_node(N1);
  N1S0.set_shard_index(0);
  // Some nodes
  auto N2 = thrift::NodeID();
  N2.set_node_index(2);
  auto N2S0 = thrift::ShardID();
  N2S0.set_node(N2);
  N2S0.set_shard_index(0);

  auto N11 = thrift::NodeID();
  N11.set_node_index(11);
  auto N11S0 = thrift::ShardID();
  N11S0.set_node(N11);
  N11S0.set_shard_index(0);

  auto N7 = thrift::NodeID();
  auto n7_addr = thrift::SocketAddress();
  // this node will be matched by address.
  n7_addr.set_address("127.0.0.7");
  n7_addr.set_address_family(thrift::SocketAddressFamily::INET);
  N7.set_address(n7_addr);

  std::vector<MaintenanceDefinition> definitions;
  // Definition 1
  //    G1 => (N1:S0) -> MAY_DISAPPEAR (and DISABLED sequencer)
  auto def1 = MaintenanceDefinition();
  def1.set_user("Autobot");
  def1.set_shards({N1S0});
  def1.set_shard_target_state(ShardOperationalState::MAY_DISAPPEAR);
  def1.set_created_on(111);
  def1.set_sequencer_nodes({N1});
  def1.set_sequencer_target_state(SequencingState::DISABLED);
  def1.set_group_id("G1");
  def1.set_priority(MaintenancePriority::MEDIUM);
  definitions.push_back(std::move(def1));

  //    G2 => (N2:S0, N11:S0) -> DRAINED (N11 SEQ DISABLED) (LOW PRIORITY)
  auto def2 = MaintenanceDefinition();
  def2.set_user("Autobot");
  def2.set_shards({N2S0, N11S0});
  def2.set_shard_target_state(ShardOperationalState::DRAINED);
  def2.set_sequencer_nodes({N11});
  def2.set_sequencer_target_state(SequencingState::DISABLED);
  def2.set_created_on(100);
  def2.set_group_id("G2");
  def2.set_priority(MaintenancePriority::LOW);
  definitions.push_back(std::move(def2));

  //    G3 => (N2:S0) -> DRAINED (HIGH PRIORITY)
  auto def3 = MaintenanceDefinition();
  def3.set_user("Autobot");
  def3.set_shards({N2S0});
  def3.set_shard_target_state(ShardOperationalState::DRAINED);
  def3.set_created_on(50);
  def3.set_group_id("G3");
  def3.set_priority(MaintenancePriority::HIGH);
  definitions.push_back(std::move(def3));

  //    G4 => (N7) -(sequencer)-> DISABLED
  auto def4 = MaintenanceDefinition();
  def4.set_user("Autobot");
  def4.set_sequencer_nodes({N7});
  def4.set_sequencer_target_state(SequencingState::DISABLED);
  def4.set_created_on(50);
  def4.set_group_id("G4");
  def4.set_priority(MaintenancePriority::MEDIUM);
  definitions.push_back(std::move(def4));

  output->set_maintenances(std::move(definitions));
  return output;
}

std::vector<ShardWorkflow> genShardWorkflows() {
  std::vector<ShardWorkflow> shard_wf;
  // N1S0
  shard_wf.emplace_back(ShardID(1, 0), nullptr);
  // N2S0
  shard_wf.emplace_back(ShardID(2, 0), nullptr);
  // N11S0
  shard_wf.emplace_back(ShardID(11, 0), nullptr);
  return shard_wf;
}

std::vector<SequencerWorkflow> genSequencerWorkflows() {
  std::vector<SequencerWorkflow> seq_wf;
  seq_wf.emplace_back(1);
  seq_wf.emplace_back(11);
  seq_wf.emplace_back(7);
  return seq_wf;
}

}}} // namespace facebook::logdevice::maintenance
